package com.springboot.cli.utils;

import cn.hutool.core.io.FileUtil;
import com.sun.star.beans.PropertyValue;
import com.sun.star.frame.XComponentLoader;
import com.sun.star.frame.XDesktop;
import com.sun.star.frame.XStorable;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.XComponentContext;
import ooo.connector.BootstrapSocketConnector;
import org.apache.commons.io.FileUtils;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.exceptions.InvalidFormatException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.math.BigInteger;

public class Docx4jUtil {
    private static final Logger logger = LoggerFactory.getLogger(Docx4jUtil.class);

    public static WordprocessingMLPackage wordPackage = null;

    public static MainDocumentPart mainDocumentPart = null;

    public static ObjectFactory objectFactory = null;

    /**
     * 创建word文档
     */
    public static void createDocx() {
        try {
            wordPackage = WordprocessingMLPackage.createPackage();
            mainDocumentPart = wordPackage.getMainDocumentPart();
            objectFactory = Context.getWmlObjectFactory();
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (wordPackage == null || mainDocumentPart == null || objectFactory == null) {
            logger.error("创建word文档失败!!!");
            wordPackage = null;
            mainDocumentPart = null;
            objectFactory = null;
        }
    }

    /**
     * 横向合并单元格
     *
     * @param mergeTable  需要合并的table
     * @param beginColumn 开始列(从0开始算起)
     * @param endColumn   结束列(从0开始算起)
     * @param row         需要合并的行(从0开始算起)
     * @param content     合并后内容
     */
    public static void mergeTdCell(Tbl mergeTable, int beginColumn, int endColumn, int row, String content) {
        Tr tr = (Tr) mergeTable.getContent().get(row);
        Tc beginTd = (Tc) tr.getContent().get(beginColumn);
        CTVerticalJc vjc = new CTVerticalJc();
        vjc.setVal(STVerticalJc.CENTER);
        beginTd.getTcPr().setVAlign(vjc);//上下垂直居中
        TcPrInner.HMerge beginMerge = new TcPrInner.HMerge();
        beginMerge.setVal("restart");
        beginTd.getTcPr().setHMerge(beginMerge);
        for (int i = beginColumn + 1; i <= endColumn; i++) {
            Tc endTd = (Tc) tr.getContent().get(i);
            TcPrInner.HMerge endMerge = new TcPrInner.HMerge();
            endMerge.setVal("continue");
            endTd.getTcPr().setHMerge(endMerge);
        }
        beginTd.getContent().clear();
        beginTd.getContent().add(mainDocumentPart.createParagraphOfText(content));
    }

    /**
     * 纵向合并单元格
     *
     * @param mergeTable 需要合并的表格
     * @param beginRow   开始行(从0开始算起)
     * @param endRow     结束行(从0算起)
     * @param column     列号(从0开始)
     */
    public static void mergeMdCell(Tbl mergeTable, int beginRow, int endRow, int column, String content) {
        CTVerticalJc vjc = new CTVerticalJc();
        vjc.setVal(STVerticalJc.CENTER);
        Tc beginTd = null;
        for (int i = beginRow; i <= endRow; i++) {
            Tr tr = (Tr) mergeTable.getContent().get(i);
            beginTd = (Tc) tr.getContent().get(column);
            TcPrInner.VMerge merge = new TcPrInner.VMerge();
            merge.setVal("restart");
            beginTd.getTcPr().setVMerge(merge);
            beginTd.getTcPr().setVAlign(vjc);//上下垂直居中
        }
        beginTd.getContent().clear();
        beginTd.getContent().add(mainDocumentPart.createParagraphOfText(content));
    }

    /**
     * 根据一个二维数据创建表格
     *
     * @param content 二维数组 带内容
     * @return
     */
    public static Tbl createDataTable(String[][] content) {
        Tbl table = objectFactory.createTbl();
        PPr ppr = new PPr();
        Jc jc = new Jc();
        jc.setVal(JcEnumeration.CENTER);
        ppr.setJc(jc);//单元格文本居中使用
        for (int i = 0; i < content.length; i++) {
            Tr dataTr = objectFactory.createTr();
            for (int j = 0; j < content[i].length; j++) {
                Tc tc = objectFactory.createTc();
                tc.setTcPr(new TcPr());
                tc.getContent().add(mainDocumentPart.createParagraphOfText(content[i][j]));
                dataTr.getContent().add(tc);
            }
            table.getContent().add(dataTr);
        }
        setTcBorders(table);
        return table;
    }

    /**
     * 保存word文件
     *
     * @param outPathFileName 输出目录+文件名 例如E:\\test\\test.docx
     */
    public static void save(String outPathFileName) {
        try {
            File file = new File(outPathFileName);
            if (!file.exists()) {
                file.createNewFile();
            }
            wordPackage.save(file);
        } catch (Docx4JException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 把初始化的实例置为空
     */
    public static void cleanResource() {
        wordPackage.clone();
        mainDocumentPart = null;
        objectFactory = null;
        logger.info("清理完成...");
    }

    /**
     * 设置单元格边框
     *
     * @param table
     */
    private static void setTcBorders(Tbl table) {
        table.setTblPr(new TblPr());// 必须设置一个TblPr，否则最后会报空指针异常
        CTBorder border = new CTBorder();
        border.setColor("auto");
        border.setSz(new BigInteger("4"));
        border.setSpace(new BigInteger("0"));
        border.setVal(STBorder.SINGLE);
        TblBorders borders = new TblBorders();
        borders.setBottom(border);
        borders.setLeft(border);
        borders.setRight(border);
        borders.setTop(border);
        borders.setInsideH(border);
        borders.setInsideV(border);
        // 获取其内部的TblPr属性设置属性
        table.getTblPr().setTblBorders(borders);
    }

    /**
     * 把word转为pdf
     *
     * @param workingDir   工作目录 就是word和pdf所在目录
     * @param docxFileName word文件名
     * @param pdfFileName  pdf文件名
     * @return
     */
    public static void convertDocxToPDF2(String workingDir, String docxFileName, String pdfFileName) {
        try {
            // Initialise
            String oooExeFolder = "D:\\libreOffice6\\program";
            XComponentContext xContext = BootstrapSocketConnector.bootstrap(oooExeFolder);
            XMultiComponentFactory xMCF = xContext.getServiceManager();
            Object oDesktop = xMCF.createInstanceWithContext(
                    "com.sun.star.frame.Desktop", xContext);
            XDesktop xDesktop = (XDesktop) UnoRuntime.queryInterface(
                    XDesktop.class, oDesktop);
            // Load the Document
            String myTemplate = docxFileName;
            if (!new File(workingDir + myTemplate).canRead()) {
                throw new RuntimeException("Cannot load template:" + new File(workingDir + myTemplate));
            }
            XComponentLoader xCompLoader = (XComponentLoader) UnoRuntime
                    .queryInterface(com.sun.star.frame.XComponentLoader.class, xDesktop);
            String sUrl = "file:///" + workingDir + myTemplate;
            PropertyValue[] propertyValues = new PropertyValue[0];
            propertyValues = new PropertyValue[1];
            propertyValues[0] = new PropertyValue();
            propertyValues[0].Name = "Hidden";
            propertyValues[0].Value = new Boolean(true);
            XComponent xComp = xCompLoader.loadComponentFromURL(
                    sUrl, "_blank", 0, propertyValues);
            // save as a PDF
            XStorable xStorable = (XStorable) UnoRuntime
                    .queryInterface(XStorable.class, xComp);
            propertyValues = new PropertyValue[2];
            propertyValues[0] = new PropertyValue();
            propertyValues[0].Name = "Overwrite";
            propertyValues[0].Value = new Boolean(true);
            propertyValues[1] = new PropertyValue();
            propertyValues[1].Name = "FilterName";
            propertyValues[1].Value = "writer_pdf_Export";
            // Appending the favoured extension to the origin document name
            String myResult = workingDir + pdfFileName;
            xStorable.storeToURL("file:///" + myResult, propertyValues);
            System.out.println("Saved " + myResult);
            // shutdown
            xComp.dispose();
            xDesktop.terminate();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void main(String[] args) {
        int row = 8;
        int column = 4;
        createDocx();
        String[][] content = new String[row][column];
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < column; j++) {
                content[i][j] = "test" + i + "-" + j;
            }
        }
        Tbl table = createDataTable(content);
        mainDocumentPart.addObject(table);
        // mergeTdCell(table,1,3,3,"测试合并");
        mergeMdCell(table, 3, 5, 1, "测试纵向合并");
        String workDir = "d:\\document\\";
        String docxFileName = "test.docx";
        save(workDir + docxFileName);
        cleanResource();
        // convertDocxToPDF2(workDir,docxFileName,docxFileName.replaceAll("docx","pdf"));
    }
}

